package com.example.communist_app_api.config.mq;

import cn.hutool.core.util.IdUtil;
import com.example.communist_app_api.db.pojoDto.NoticeEntity;
import com.example.communist_app_api.db.pojoDto.NoticeRefEntity;
import com.example.communist_app_api.service.NoticeService;
import com.example.communist_app_api.util.StringUtil;
import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <h4>community-uniapp</h4>
 * <p></p>
 *
 * @author : Lowell
 * @date : 2023-01-15 19:25
 **/
@Component
@Slf4j
public class NoticeTask {

    @Autowired
    private ConnectionFactory factory;

    @Autowired
    private NoticeService noticeService;

    public static final String EXCHANGE_NAME="topic_logs";

    public static final String QUEUE_NOTICE_PREFIX="noticeQueue_";

    public static final String QUEUE_ANNOUNCER_PREFIX="AnnouncerQueue_";

    public static final String ANNOUNCER_ROUTING_KEY="announcer";


    /**
     * 发通知专用
     * @param senderId 发送者Id
     * @param receiverId 接收者Id
     * @param noticeName 消息名字
     * @param msg   消息内容
     * param type 0为通知 1为公告
     */
    public void sendNotice(Integer senderId, String receiverId, String noticeName, String msg) {
        NoticeEntity notice=new NoticeEntity();
        notice.setSenderId(senderId);
        notice.setUuid(IdUtil.simpleUUID());
        notice.setSendTime(new Date());
        notice.setSenderName(noticeName);
        notice.setMsg(msg);
        notice.setType("0");
        sendNotice(receiverId, notice);
    }

    /**
     * 发系统通知专用
     * @param receiverId
     * @param msg
     * param type 0为通知 1为公告
     */
    public void sendSystemNotice(String receiverId,String msg) {
        NoticeEntity notice=new NoticeEntity();
        notice.setSenderId(0);
        notice.setUuid(IdUtil.simpleUUID());
        notice.setSendTime(new Date());
        notice.setSenderName("系统消息");
        notice.setMsg(msg);
        notice.setType("0");
        sendNotice(receiverId, notice);
    }

    /**
     * 发公告专用方法
     * @param senderId 发送Id
     * @param senderName 发送者名字
     * @param msg 内容
     *  param type 0为通知 1为公告
     */
    public void sendAnnouncer(Integer senderId, String senderName, String msg,List<Integer> userIdList) {
        NoticeEntity announcer=new NoticeEntity();
        announcer.setSenderId(senderId);
        announcer.setUuid(IdUtil.simpleUUID());
        announcer.setSendTime(new Date());
        announcer.setSenderName(senderName);
        announcer.setMsg(msg);
        announcer.setType("1");
        sendAnnouncer(announcer,userIdList);
    }


    @Async
    public void sendNoticeAsync(Integer senderId, String receiverId, String noticeName, String msg) {
        sendNotice(senderId,receiverId,noticeName,msg);
    }

    @Async
    public void sendSystemNoticeAsync(String receiverId,String msg) {
      sendSystemNotice(receiverId,msg);
    }

    @Async
    public void sendSystemNoticeBatchAsync(List<Integer> receiverIdList, String msg,String senderName){
        sendSystemNoticeBatch(receiverIdList,msg,senderName);
    }
    /**
     * 批量发送系统消息用
     * @param receiverIdList 批量用户接收
     * @param msg 通知内容
     *            param type 0为通知 1为公告
     */
    public void sendSystemNoticeBatch(List<Integer> receiverIdList, String msg,String senderName) {
        NoticeEntity notice=new NoticeEntity();
        notice.setSenderId(0);
        notice.setUuid(IdUtil.simpleUUID());
        notice.setSendTime(new Date());
        if (StringUtil.isEmpty(senderName)){
            notice.setSenderName("系统通知");
        }else {
            notice.setSenderName(senderName);
        }
        notice.setMsg(msg);
        notice.setType("0");
        String id =noticeService.insertNotice(notice);
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel();
        ) {
            HashMap map = new HashMap();
            map.put("noticeId", id);
            AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().headers(map).build();
            for (Integer receiverId:receiverIdList) {
                channel.queueDeclare(QUEUE_NOTICE_PREFIX+receiverId, true, false, false, null);
                channel.basicPublish("", QUEUE_NOTICE_PREFIX+receiverId, properties, notice.getMsg().getBytes());
            }
             log.debug("通知发送成功");
        } catch (Exception e) {
            log.error("执行异常", e);
            throw new RuntimeException("向MQ发送通知失败");
        }
    }


    //异步发公告方法
    @Async
    public void sendAnnouncerAsync(Integer senderId, String senderName, String msg,String organizationId,List<Integer> userIdList) {
        sendAnnouncer(senderId,senderName,msg,userIdList);
    }


    private void sendNotice(String queueName, NoticeEntity entity) {
        String id =noticeService.insertNotice(entity);
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel();
        ) {
            channel.queueDeclare(QUEUE_NOTICE_PREFIX+queueName, true, false, false, null);
            HashMap map = new HashMap();
            map.put("noticeId", id);
            AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().headers(map).build();
            channel.basicPublish("", QUEUE_NOTICE_PREFIX+queueName, properties, entity.getMsg().getBytes());
            log.debug("通知发送成功");
        } catch (Exception e) {
            log.error("执行异常", e);
            throw new RuntimeException("向MQ发送通知失败");
        }
    }

    //公告是批量发多人
    private void sendAnnouncer(NoticeEntity entity,List<Integer> userIdList) {
        String id =noticeService.insertNotice(entity);
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel();
        ) {
            HashMap map = new HashMap();
            map.put("noticeId", id);//这个key别改
            AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().headers(map).build();
            for (Integer userId: userIdList) {
                channel.queueDeclare(QUEUE_NOTICE_PREFIX+userId, true, false, false, null);
                channel.basicPublish("", QUEUE_NOTICE_PREFIX+userId, properties, entity.getMsg().getBytes());
            }
            log.debug("公告发送成功");
        } catch (Exception e) {
            log.error("执行异常", e);
            throw new RuntimeException("向MQ发送公告失败");
        }
    }


    private int receive(String queueName) {
        int i = 0;
        try(

                Connection connection = factory.newConnection();
                Channel channel = connection.createChannel();
        ) {

            //channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
            // 从队列中获取消息，不自动确认
            channel.queueDeclare(QUEUE_NOTICE_PREFIX+queueName, true, false, false, null);
            //channel.queueBind(QUEUE_NOTICE_PREFIX+queueName,EXCHANGE_NAME,"notice."+queueName);
            //channel.queueDeclare(QUEUE_ANNOUNCER_PREFIX+queueName, true, false, false, null);
            //channel.queueBind(QUEUE_ANNOUNCER_PREFIX+queueName,EXCHANGE_NAME,ANNOUNCER_ROUTING_KEY+"."+queueName);

            while (true) {
                GetResponse response = channel.basicGet(QUEUE_NOTICE_PREFIX+queueName, false);
                if (response != null) {
                    AMQP.BasicProperties properties = response.getProps();
                    Map<String, Object> map = properties.getHeaders();
                    String noticeId = map.get("noticeId").toString();
                    byte[] body = response.getBody();
                    String message = new String(body);
                    log.debug("从RabbitMQ接收的消息：" + message);
                   NoticeRefEntity entity = new NoticeRefEntity();
                    entity.setNoticeId(noticeId);
                    entity.setReceiverId(Integer.parseInt(queueName));
                    entity.setReadFlag(false);
                    entity.setLastFlag(true);
                    noticeService.insertNoticeRef(entity);
                    long deliveryTag = response.getEnvelope().getDeliveryTag();
                    channel.basicAck(deliveryTag, false);
                    i++;
                }
                else {
                    break;
                }
            }
        } catch (Exception e) {
            log.error("执行异常", e);
            throw new RuntimeException("接收消息失败");
        }
        return i;
    }

    @Async
    public int receiveAsync(String queueName) {
        return receive(queueName);
    }

    public void deleteQueue(String queueName){
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel();
        ) {
            channel.queueDelete(queueName);
            log.debug("消息队列成功删除");
        }catch (Exception e) {
            log.error("删除队列失败", e);
            throw new RuntimeException("删除队列失败");
        }
    }

    @Async
    public void deleteQueueAsync(String queueName){
        deleteQueue(queueName);
    }
}
